home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / source.exe / POSIX / FIND / FUNCTION.C < prev    next >
C/C++ Source or Header  |  1993-06-23  |  25KB  |  1,291 lines

  1. /*
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Cimarron D. Taylor of the University of California, Berkeley.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)function.c    5.17 (Berkeley) 5/24/91";
  39. #endif /* not lint */
  40. #ifdef DF_POSIX /* DF_MSS */
  41. #include <misc.h>
  42. #include <bsdlib.h>
  43. #else
  44. #include <sys/param.h>
  45. #endif
  46. #include <sys/stat.h>
  47. #include <sys/wait.h>
  48. #include <sys/mount.h>
  49. #include <stdlib.h>
  50. #include <errno.h>
  51. #include <grp.h>
  52. #include <pwd.h>
  53. #include <fts.h>
  54. #include <tzfile.h>
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #include <string.h>
  58. #if _POSIX_SOURCE
  59. # include <unistd.h>
  60. #endif
  61. #include "find.h"
  62.  
  63. #define    FIND_EQUAL    0
  64. #define    FIND_LESSTHAN    1
  65. #define    FIND_GREATER    2
  66.  
  67. #define    COMPARE(a, b) { \
  68.     switch(plan->flags) { \
  69.     case FIND_EQUAL: \
  70.         return(a == b); \
  71.     case FIND_LESSTHAN: \
  72.         return(a < b); \
  73.     case FIND_GREATER: \
  74.         return(a > b); \
  75.     } \
  76.     return(0); \
  77. }
  78. #if WIN_NT
  79.  
  80. extern char *group_from_gid __P((gid_t, int));
  81. extern char *user_from_uid __P((uid_t, int));
  82. extern void deglobulate __P((void));
  83. extern pid_t ppid;
  84. extern int globulation;
  85. #endif
  86.  
  87. static PLAN *palloc __P((enum ntype, int (*)(PLAN *, FTSENT *)));
  88.  
  89. /*
  90.  * find_parsenum --
  91.  *    Parse a string of the form [+-]# and return the value.
  92.  */
  93. long
  94. #if __STDC__
  95. find_parsenum (PLAN *plan, char *option, char *str, char *endch)
  96. #else
  97. find_parsenum(plan, option, str, endch)
  98.     PLAN *plan;
  99.     char *option, *str, *endch;
  100. #endif
  101. {
  102.     long value;
  103.     char *endchar;        /* pointer to character ending conversion */
  104.     
  105.     /* determine comparison from leading + or - */
  106.     switch(*str) {
  107.     case '+':
  108.         ++str;
  109.         plan->flags = FIND_GREATER;
  110.         break;
  111.     case '-':
  112.         ++str;
  113.         plan->flags = FIND_LESSTHAN;
  114.         break;
  115.     default:
  116.         plan->flags = FIND_EQUAL;
  117.         break;
  118.     }
  119.     
  120.     /*
  121.      * convert the string with strtol().  Note, if strtol() returns zero
  122.      * and endchar points to the beginning of the string we know we have
  123.      * a syntax error.
  124.      */
  125.     value = strtol(str, &endchar, 10);
  126.     if (!value && endchar == str ||
  127.         endchar[0] && (!endch || endchar[0] != *endch))
  128.         err("%s: %s", option, "illegal numeric value");
  129.     if (endch)
  130.         *endch = endchar[0];
  131.     return(value);
  132. }
  133.  
  134. /*
  135.  * -atime n functions --
  136.  *
  137.  *    True if the difference between the file access time and the
  138.  *    current time is n 24 hour periods.
  139.  *
  140.  */
  141. int
  142. #if __STDC__
  143. f_atime (PLAN *plan, FTSENT *entry)
  144. #else
  145. f_atime(plan, entry)
  146.     PLAN *plan;
  147.     FTSENT *entry;
  148. #endif
  149. {
  150.     extern time_t now;
  151.  
  152.     COMPARE((now - entry->fts_statb.st_atime +
  153.         SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
  154. }
  155.  
  156. PLAN *
  157. #if __STDC__
  158. c_atime (char *arg)
  159. #else
  160. c_atime(arg)
  161.     char *arg;
  162. #endif
  163. {
  164.     PLAN *new;
  165.  
  166.     ftsoptions &= ~FTS_NOSTAT;
  167.  
  168.     new = palloc(N_ATIME, f_atime);
  169.     new->t_data = find_parsenum(new, "-atime", arg, NULL);
  170.     return(new);
  171. }
  172. /*
  173.  * -ctime n functions --
  174.  *
  175.  *    True if the difference between the last change of file
  176.  *    status information and the current time is n 24 hour periods.
  177.  */
  178. int
  179. #if __STDC__
  180. f_ctime (PLAN *plan, FTSENT *entry)
  181. #else
  182. f_ctime(plan, entry)
  183.     PLAN *plan;
  184.     FTSENT *entry;
  185. #endif
  186. {
  187.     extern time_t now;
  188.  
  189.     COMPARE((now - entry->fts_statb.st_ctime +
  190.         SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
  191. }
  192.  
  193. PLAN *
  194. #if __STDC__
  195. c_ctime (char *arg)
  196. #else
  197. c_ctime(arg)
  198.     char *arg;
  199. #endif
  200. {
  201.     PLAN *new;
  202.  
  203.     ftsoptions &= ~FTS_NOSTAT;
  204.  
  205.     new = palloc(N_CTIME, f_ctime);
  206.     new->t_data = find_parsenum(new, "-ctime", arg, (char *)NULL);
  207.     return(new);
  208. }
  209.  
  210. /*
  211.  * -depth functions --
  212.  *
  213.  *    Always true, causes descent of the directory hierarchy to be done
  214.  *    so that all entries in a directory are acted on before the directory
  215.  *    itself.
  216.  */
  217. /* ARGSUSED */
  218. #if __STDC__
  219. f_always_true (PLAN *plan, FTSENT *entry)
  220. #else
  221. f_always_true(plan, entry)
  222.     PLAN *plan;
  223.     FTSENT *entry;
  224. #endif
  225. {
  226. #if WIN_NT
  227.     if (plan == NULL || entry == NULL)
  228.         ;
  229. #endif
  230.     return(1);
  231. }
  232.  
  233. PLAN *
  234. #if __STDC__
  235. c_depth (void)
  236. #else
  237. c_depth()
  238. #endif
  239. {
  240.     isdepth = 1;
  241.  
  242.     return(palloc(N_DEPTH, f_always_true));
  243. }
  244.  
  245. /*
  246.  * [-exec | -ok] utility [arg ... ] ; functions --
  247.  *
  248.  *    True if the executed utility returns a zero value as exit status.
  249.  *    The end of the primary expression is delimited by a semicolon.  If
  250.  *    "{}" occurs anywhere, it gets replaced by the current pathname.
  251.  *    The current directory for the execution of utility is the same as
  252.  *    the current directory when the find utility was started.
  253.  *
  254.  *    The primary -ok is different in that it requests affirmation of the
  255.  *    user before executing the utility.
  256.  */
  257. #if __STDC__
  258. f_exec (register PLAN *plan, FTSENT *entry)
  259. #else
  260. f_exec(plan, entry)
  261.     register PLAN *plan;
  262.     FTSENT *entry;
  263. #endif
  264. {
  265. #ifdef _POSIX_SOURCE /* DF_DSC */
  266.         extern char curr_dir[PATH_MAX +1];
  267. #else
  268.     extern int dotfd;
  269. #endif
  270.     register int cnt;
  271.     pid_t pid;
  272.     int status;
  273.  
  274.     for (cnt = 0; plan->e_argv[cnt]; ++cnt)
  275.         if (plan->e_len[cnt])
  276.             brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
  277.                 entry->fts_path, plan->e_len[cnt]);
  278.  
  279.     if (plan->flags && !queryuser(plan->e_argv))
  280.         return(0);
  281.  
  282. #if _POSIX_SOURCE
  283.     switch(pid = fork()) {
  284. #else
  285.     switch(pid = vfork()) {
  286. #endif
  287.     case -1:
  288.         err("fork: %s", strerror(errno));
  289.         /* NOTREACHED */
  290.     case 0:
  291. #ifdef _POSIX_SOURCE /* DF_DSC: because fchdir not in POSIX.1 */
  292.                 if (chdir(curr_dir)) {
  293. #else
  294.         if (fchdir(dotfd)) {
  295. #endif
  296.             (void)fprintf(stderr,
  297.                 "find: chdir: %s\n", strerror(errno));
  298. #if WIN_NT
  299.             if (ppid == (pid_t) 1 && globulation == 0)
  300.                 deglobulate();
  301. #endif
  302.             _exit(EXIT_FAILURE);
  303.         }
  304.         execvp(plan->e_argv[0], plan->e_argv);
  305.         (void)fprintf(stderr,
  306.             "find: %s: %s\n", plan->e_argv[0], strerror(errno));
  307. #if WIN_NT
  308.         if (ppid == (pid_t) 1 && globulation == 0)
  309.             deglobulate();
  310. #endif
  311.         _exit(EXIT_FAILURE);
  312.     }
  313.     pid = waitpid(pid, &status, 0);
  314.     return(pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
  315. }
  316.  
  317. /*
  318.  * c_exec --
  319.  *    build three parallel arrays, one with pointers to the strings passed
  320.  *    on the command line, one with (possibly duplicated) pointers to the
  321.  *    argv array, and one with integer values that are lengths of the
  322.  *    strings, but also flags meaning that the string has to be massaged.
  323.  */
  324. PLAN *
  325. #if __STDC__
  326. c_exec (char ***argvp, int isok)
  327. #else
  328. c_exec(argvp, isok)
  329.     char ***argvp;
  330.     int isok;
  331. #endif
  332. {
  333.     PLAN *new;            /* node returned */
  334.     register int cnt;
  335.     register char **argv, **ap, *p;
  336.  
  337.     isoutput = 1;
  338.     
  339.     new = palloc(N_EXEC, f_exec);
  340.     new->flags = isok;
  341.  
  342.     for (ap = argv = *argvp;; ++ap) {
  343.         if (!*ap)
  344.             err("%s: %s",
  345.                 isok ? "-ok" : "-exec", "no terminating \";\"");
  346.         if (**ap == ';')
  347.             break;
  348.     }
  349.  
  350.     cnt = ap - *argvp + 1;
  351.     new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *));
  352.     new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *));
  353.     new->e_len = (int *)emalloc((u_int)cnt * sizeof(int));
  354.  
  355.     for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
  356.         new->e_orig[cnt] = *argv;
  357.         for (p = *argv; *p; ++p)
  358.             if (p[0] == '{' && p[1] == '}') {
  359.                 new->e_argv[cnt] = emalloc((u_int)MAXPATHLEN);
  360.                 new->e_len[cnt] = MAXPATHLEN;
  361.                 break;
  362.             }
  363.         if (!*p) {
  364.             new->e_argv[cnt] = *argv;
  365.             new->e_len[cnt] = 0;
  366.         }
  367.     }
  368.     new->e_argv[cnt] = new->e_orig[cnt] = NULL;
  369.  
  370.     *argvp = argv + 1;
  371.     return(new);
  372. }
  373.  
  374. /*
  375.  * -follow functions --
  376.  *
  377.  *    Always true, causes symbolic links to be followed on a global
  378.  *    basis.
  379.  */
  380. PLAN *
  381. #if __STDC__
  382. c_follow (void)
  383. #else
  384. c_follow()
  385. #endif
  386. {
  387.     ftsoptions &= ~FTS_PHYSICAL;
  388.     ftsoptions |= FTS_LOGICAL;
  389.  
  390.     return(palloc(N_FOLLOW, f_always_true));
  391. }
  392.  
  393. /*
  394.  * -fstype functions --
  395.  *
  396.  *    True if the file is of a certain type.
  397.  */
  398. int
  399. #if __STDC__
  400. f_fstype (PLAN *plan, FTSENT *entry)
  401. #else
  402. f_fstype(plan, entry)
  403.     PLAN *plan;
  404.     FTSENT *entry;
  405. #endif
  406. {
  407.     static dev_t curdev;    /* need a guaranteed illegal dev value */
  408.     static int first = 1;
  409.     struct statfs sb;
  410.     static short val;
  411.     char *p, save[2];
  412.  
  413.     /* only check when we cross mount point */
  414.     if (first || curdev != entry->fts_statb.st_dev) {
  415.         curdev = entry->fts_statb.st_dev;
  416.  
  417.         /*
  418.          * Statfs follows symlinks; find wants the link's file system,
  419.          * not where it points.
  420.          */
  421.         if (entry->fts_info == FTS_SL ||
  422.             entry->fts_info == FTS_SLNONE) {
  423.             if ((p = rindex(entry->fts_accpath, '/')) != NULL)
  424.                 ++p;
  425.             else
  426.                 p = entry->fts_accpath;
  427.             save[0] = p[0];
  428.             p[0] = '.';
  429.             save[1] = p[1];
  430.             p[1] = '\0';
  431.             
  432.         } else 
  433.             p = NULL;
  434. #ifdef _POSIX_SOURCE /* DF_DSC: no symlinks or mounts in NT POSIX */
  435. #else
  436.         if (statfs(entry->fts_accpath, &sb))
  437.             err("%s: %s", entry->fts_accpath, strerror(errno));
  438. #endif
  439.  
  440.         if (p) {
  441.             p[0] = save[0];
  442.             p[1] = save[1];
  443.         }
  444.  
  445.         first = 0;
  446.         val = (short) ((plan->flags == MOUNT_NONE) ? sb.f_flags : sb.f_type);
  447.     }
  448.     return(plan->flags == MOUNT_NONE ?
  449.         val & MNT_LOCAL : val == plan->flags);
  450. }
  451.  
  452. PLAN *
  453. #if __STDC__
  454. c_fstype (char *arg)
  455. #else
  456. c_fstype(arg)
  457.     char *arg;
  458. #endif
  459. {
  460.     register PLAN *new;
  461.     
  462.     ftsoptions &= ~FTS_NOSTAT;
  463.     
  464.     new = palloc(N_FSTYPE, f_fstype);
  465.     switch(*arg) {
  466.     case 'l':
  467.         if (!strcmp(arg, "local")) {
  468.             new->flags = MOUNT_NONE;
  469.             return(new);
  470.         }
  471.         break;
  472.     case 'm':
  473.         if (!strcmp(arg, "mfs")) {
  474.             new->flags = MOUNT_MFS;
  475.             return(new);
  476.         }
  477.         break;
  478.     case 'n':
  479.         if (!strcmp(arg, "nfs")) {
  480.             new->flags = MOUNT_NFS;
  481.             return(new);
  482.         }
  483.         break;
  484.     case 'p':
  485.         if (!strcmp(arg, "pc")) {
  486.             new->flags = MOUNT_PC;
  487.             return(new);
  488.         }
  489.         break;
  490.     case 'u':
  491.         if (!strcmp(arg, "ufs")) {
  492.             new->flags = MOUNT_UFS;
  493.             return(new);
  494.         }
  495.         break;
  496.     }
  497.     err("unknown file type %s", arg);
  498.     /* NOTREACHED */
  499. }
  500.  
  501. /*
  502.  * -group gname functions --
  503.  *
  504.  *    True if the file belongs to the group gname.  If gname is numeric and
  505.  *    an equivalent of the getgrnam() function does not return a valid group
  506.  *    name, gname is taken as a group ID.
  507.  */
  508. int
  509. #if __STDC__
  510. f_group (PLAN *plan, FTSENT *entry)
  511. #else
  512. f_group(plan, entry)
  513.     PLAN *plan;
  514.     FTSENT *entry;
  515. #endif
  516. {
  517.     return(entry->fts_statb.st_gid == plan->g_data);
  518. }
  519.  
  520. PLAN *
  521. #if __STDC__
  522. c_group (char *gname)
  523. #else
  524. c_group(gname)
  525.     char *gname;
  526. #endif
  527. {
  528.     PLAN *new;
  529.     struct group *g;
  530.     gid_t gid;
  531.     
  532.     ftsoptions &= ~FTS_NOSTAT;
  533.  
  534.     g = getgrnam(gname);
  535.     if (g == NULL) {
  536.         gid = atoi(gname);
  537.         if (gid == 0 && gname[0] != '0')
  538.             err("%s: %s", "-group", "no such group");
  539.     } else
  540.         gid = g->gr_gid;
  541.     
  542.     new = palloc(N_GROUP, f_group);
  543.     new->g_data = gid;
  544.     return(new);
  545. }
  546.  
  547. /*
  548.  * -inum n functions --
  549.  *
  550.  *    True if the file has inode # n.
  551.  */
  552. int
  553. #if __STDC__
  554. f_inum (PLAN *plan, FTSENT *entry)
  555. #else
  556. f_inum(plan, entry)
  557.     PLAN *plan;
  558.     FTSENT *entry;
  559. #endif
  560. {
  561.     COMPARE(entry->fts_statb.st_ino, plan->i_data);
  562. }
  563.  
  564. PLAN *
  565. #if __STDC__
  566. c_inum (char *arg)
  567. #else
  568. c_inum(arg)
  569.     char *arg;
  570. #endif
  571. {
  572.     PLAN *new;
  573.     
  574.     ftsoptions &= ~FTS_NOSTAT;
  575.     
  576.     new = palloc(N_INUM, f_inum);
  577.     new->i_data = find_parsenum(new, "-inum", arg, (char *)NULL);
  578.     return(new);
  579. }
  580.  
  581. /*
  582.  * -links n functions --
  583.  *
  584.  *    True if the file has n links.
  585.  */
  586. int
  587. #if __STDC__
  588. f_links (PLAN *plan, FTSENT *entry)
  589. #else
  590. f_links(plan, entry)
  591.     PLAN *plan;
  592.     FTSENT *entry;
  593. #endif
  594. {
  595.     COMPARE(entry->fts_statb.st_nlink, plan->l_data);
  596. }
  597.  
  598. PLAN *
  599. #if __STDC__
  600. c_links (char *arg)
  601. #else
  602. c_links(arg)
  603.     char *arg;
  604. #endif
  605. {
  606.     PLAN *new;
  607.     
  608.     ftsoptions &= ~FTS_NOSTAT;
  609.     
  610.     new = palloc(N_LINKS, f_links);
  611.     new->l_data = (nlink_t)find_parsenum(new, "-links", arg, (char *)NULL);
  612.     return(new);
  613. }
  614.  
  615. /*
  616.  * -ls functions --
  617.  *
  618.  *    Always true - prints the current entry to stdout in "ls" format.
  619.  */
  620. /* ARGSUSED */
  621. int
  622. #if __STDC__
  623. f_ls (PLAN *plan, FTSENT *entry)
  624. #else
  625. f_ls(plan, entry)
  626.     PLAN *plan;
  627.     FTSENT *entry;
  628. #endif
  629. {
  630. #if WIN_NT
  631.     if (plan == NULL)
  632.         ;
  633. #endif
  634.     printlong(entry->fts_path, entry->fts_accpath, &entry->fts_statb);
  635.     return(1);
  636. }
  637.  
  638. PLAN *
  639. #if __STDC__
  640. c_ls (void)
  641. #else
  642. c_ls()
  643. #endif
  644. {
  645.     ftsoptions &= ~FTS_NOSTAT;
  646.     isoutput = 1;
  647.     
  648.     return(palloc(N_LS, f_ls));
  649. }
  650.  
  651. /*
  652.  * -name functions --
  653.  *
  654.  *    True if the basename of the filename being examined
  655.  *    matches pattern using Pattern Matching Notation S3.14
  656.  */
  657. int
  658. #if __STDC__
  659. f_name (PLAN *plan, FTSENT *entry)
  660. #else
  661. f_name(plan, entry)
  662.     PLAN *plan;
  663.     FTSENT *entry;
  664. #endif
  665. {
  666.     return(fnmatch(plan->c_data, entry->fts_name, FNM_QUOTE));
  667. }
  668.  
  669. PLAN *
  670. #if __STDC__
  671. c_name (char *pattern)
  672. #else
  673. c_name(pattern)
  674.     char *pattern;
  675. #endif
  676. {
  677.     PLAN *new;
  678.  
  679.     new = palloc(N_NAME, f_name);
  680.     new->c_data = pattern;
  681.     return(new);
  682. }
  683.  
  684. /*
  685.  * -newer file functions --
  686.  *
  687.  *    True if the current file has been modified more recently
  688.  *    then the modification time of the file named by the pathname
  689.  *    file.
  690.  */
  691. int
  692. #if __STDC__
  693. f_newer (PLAN *plan, FTSENT *entry)
  694. #else
  695. f_newer(plan, entry)
  696.     PLAN *plan;
  697.     FTSENT *entry;
  698. #endif
  699. {
  700.     return(entry->fts_statb.st_mtime > plan->t_data);
  701. }
  702.  
  703. PLAN *
  704. #if __STDC__
  705. c_newer (char *filename)
  706. #else
  707. c_newer(filename)
  708.     char *filename;
  709. #endif
  710. {
  711.     PLAN *new;
  712.     struct stat sb;
  713.     
  714.     ftsoptions &= ~FTS_NOSTAT;
  715.  
  716.     if (stat(filename, &sb))
  717.         err("%s: %s", filename, strerror(errno));
  718.     new = palloc(N_NEWER, f_newer);
  719.     new->t_data = sb.st_mtime;
  720.     return(new);
  721. }
  722.  
  723. /*
  724.  * -nogroup functions --
  725.  *
  726.  *    True if file belongs to a user ID for which the equivalent
  727.  *    of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
  728.  */
  729. /* ARGSUSED */
  730. int
  731. #if __STDC__
  732. f_nogroup (PLAN *plan, FTSENT *entry)
  733. #else
  734. f_nogroup(plan, entry)
  735.     PLAN *plan;
  736.     FTSENT *entry;
  737. #endif
  738. {
  739. #if !WIN_NT
  740.     char *group_from_gid();
  741. #endif
  742.  
  743. #if WIN_NT
  744.     if (plan == NULL)
  745.         ;
  746. #endif
  747.     return(group_from_gid(entry->fts_statb.st_gid, 1) ? 1 : 0);
  748. }
  749.  
  750. PLAN *
  751. #if __STDC__
  752. c_nogroup (void)
  753. #else
  754. c_nogroup()
  755. #endif
  756. {
  757.     ftsoptions &= ~FTS_NOSTAT;
  758.  
  759.     return(palloc(N_NOGROUP, f_nogroup));
  760. }
  761.  
  762. /*
  763.  * -nouser functions --
  764.  *
  765.  *    True if file belongs to a user ID for which the equivalent
  766.  *    of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
  767.  */
  768. /* ARGSUSED */
  769. int
  770. #if __STDC__
  771. f_nouser (PLAN *plan, FTSENT *entry)
  772. #else
  773. f_nouser(plan, entry)
  774.     PLAN *plan;
  775.     FTSENT *entry;
  776. #endif
  777. {
  778. #if !WIN_NT
  779.     char *user_from_uid();
  780. #endif
  781.  
  782. #if WIN_NT
  783.     if (plan == NULL)
  784.         ;
  785. #endif
  786.     return(user_from_uid(entry->fts_statb.st_uid, 1) ? 1 : 0);
  787. }
  788.  
  789. PLAN *
  790. #if __STDC__
  791. c_nouser (void)
  792. #else
  793. c_nouser()
  794. #endif
  795. {
  796.     ftsoptions &= ~FTS_NOSTAT;
  797.  
  798.     return(palloc(N_NOUSER, f_nouser));
  799. }
  800.  
  801. /*
  802.  * -perm functions --
  803.  *
  804.  *    The mode argument is used to represent file mode bits.  If it starts
  805.  *    with a leading digit, it's treated as an octal mode, otherwise as a
  806.  *    symbolic mode.
  807.  */
  808. int
  809. #if __STDC__
  810. f_perm (PLAN *plan, FTSENT *entry)
  811. #else
  812. f_perm(plan, entry)
  813.     PLAN *plan;
  814.     FTSENT *entry;
  815. #endif
  816. {
  817.     mode_t mode;
  818.  
  819. #ifdef _POSIX_SOURCE /* DF_DSC: no sticky bit in POSIX */
  820.     mode = entry->fts_statb.st_mode &
  821.         (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO);
  822. #else
  823.     mode = entry->fts_statb.st_mode &
  824.         (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
  825. #endif
  826.     if (plan->flags)
  827.         return((plan->m_data | mode) == mode);
  828.     else
  829.         return(mode == plan->m_data);
  830.     /* NOTREACHED */
  831. }
  832.  
  833. PLAN *
  834. #if __STDC__
  835. c_perm (char *perm)
  836. #else
  837. c_perm(perm)
  838.     char *perm;
  839. #endif
  840. {
  841.     PLAN *new;
  842.     mode_t *set;
  843.  
  844.     ftsoptions &= ~FTS_NOSTAT;
  845.  
  846.     new = palloc(N_PERM, f_perm);
  847.  
  848.     if (*perm == '-') {
  849.         new->flags = 1;
  850.         ++perm;
  851.     }
  852.  
  853.     if ((set = setmode(perm)) == NULL)
  854.         err("%s: %s", "-perm", "illegal mode string");
  855.  
  856.     new->m_data = getmode(set, 0);
  857.     return(new);
  858. }
  859.  
  860. /*
  861.  * -print functions --
  862.  *
  863.  *    Always true, causes the current pathame to be written to
  864.  *    standard output.
  865.  */
  866. /* ARGSUSED */
  867. int
  868. #if __STDC__
  869. f_print (PLAN *plan, FTSENT *entry)
  870. #else
  871. f_print(plan, entry)
  872.     PLAN *plan;
  873.     FTSENT *entry;
  874. #endif
  875. {
  876. #if WIN_NT
  877.     if (plan == NULL)
  878.         ;
  879. #endif
  880.     (void)printf("%s\n", entry->fts_path);
  881.     return(1);
  882. }
  883.  
  884. PLAN *
  885. #if _STDC__
  886. c_print (void)
  887. #else
  888. c_print()
  889. #endif
  890. {
  891.     isoutput = 1;
  892.  
  893.     return(palloc(N_PRINT, f_print));
  894. }
  895.  
  896. /*
  897.  * -prune functions --
  898.  *
  899.  *    Prune a portion of the hierarchy.
  900.  */
  901. /* ARGSUSED */
  902. int
  903. #if __STDC__
  904. f_prune (PLAN *plan, FTSENT *entry)
  905. #else
  906. f_prune(plan, entry)
  907.     PLAN *plan;
  908.     FTSENT *entry;
  909. #endif
  910. {
  911.     extern FTS *tree;
  912.  
  913. #if WIN_NT
  914.     if (plan == NULL)
  915.         ;
  916. #endif
  917.     if (fts_set(tree, entry, FTS_SKIP))
  918.         err("%s: %s", entry->fts_path, strerror(errno));
  919.     return(1);
  920. }
  921.  
  922. PLAN *
  923. #if __STDC__
  924. c_prune (void)
  925. #else
  926. c_prune()
  927. #endif
  928. {
  929.     return(palloc(N_PRUNE, f_prune));
  930. }
  931.  
  932. /*
  933.  * -size n[c] functions --
  934.  *
  935.  *    True if the file size in bytes, divided by an implementation defined
  936.  *    value and rounded up to the next integer, is n.  If n is followed by
  937.  *    a c, the size is in bytes.
  938.  */
  939. #define    FIND_SIZE    512
  940. static int divsize = 1;
  941.  
  942. int
  943. #if __STDC__
  944. f_size (PLAN *plan, FTSENT *entry)
  945. #else
  946. f_size(plan, entry)
  947.     PLAN *plan;
  948.     FTSENT *entry;
  949. #endif
  950. {
  951.     off_t size;
  952.  
  953.     size = divsize ? (entry->fts_statb.st_size + FIND_SIZE - 1) /
  954.         FIND_SIZE : entry->fts_statb.st_size;
  955.     COMPARE(size, plan->o_data);
  956. }
  957.  
  958. PLAN *
  959. #if __STDC__
  960. c_size (char *arg)
  961. #else
  962. c_size(arg)
  963.     char *arg;
  964. #endif
  965. {
  966.     PLAN *new;
  967.     char endch;
  968.     
  969.     ftsoptions &= ~FTS_NOSTAT;
  970.  
  971.     new = palloc(N_SIZE, f_size);
  972.     new->o_data = find_parsenum(new, "-size", arg, &endch);
  973.     if (endch == 'c')
  974.         divsize = 0;
  975.     return(new);
  976. }
  977.  
  978. /*
  979.  * -type c functions --
  980.  *
  981.  *    True if the type of the file is c, where c is b, c, d, p, or f for
  982.  *    block special file, character special file, directory, FIFO, or
  983.  *    regular file, respectively.
  984.  */
  985. int
  986. #if __STDC__
  987. f_type (PLAN *plan, FTSENT *entry)
  988. #else
  989. f_type(plan, entry)
  990.     PLAN *plan;
  991.     FTSENT *entry;
  992. #endif
  993. {
  994.     return((entry->fts_statb.st_mode & S_IFMT) == plan->m_data);
  995. }
  996.  
  997. PLAN *
  998. #if __STDC__
  999. c_type (char *typestring)
  1000. #else
  1001. c_type(typestring)
  1002.     char *typestring;
  1003. #endif
  1004. {
  1005.     PLAN *new;
  1006.     mode_t  mask;
  1007.     
  1008.     ftsoptions &= ~FTS_NOSTAT;
  1009.  
  1010.     switch (typestring[0]) {
  1011.     case 'b':
  1012.         mask = S_IFBLK;
  1013.         break;
  1014.     case 'c':
  1015.         mask = S_IFCHR;
  1016.         break;
  1017.     case 'd':
  1018.         mask = S_IFDIR;
  1019.         break;
  1020.     case 'f':
  1021.         mask = S_IFREG;
  1022.         break;
  1023. #ifdef _POSIX_SOURCE /* DF_DSC */
  1024. #else
  1025.     case 'l':
  1026.         mask = S_IFLNK;
  1027.         break;
  1028. #endif
  1029.     case 'p':
  1030.         mask = S_IFIFO;
  1031.         break;
  1032. #ifdef _POSIX_SOURCE /* DF_DSC */
  1033. #else
  1034.     case 's':
  1035.         mask = S_IFSOCK;
  1036.         break;
  1037. #endif
  1038.     default:
  1039.         err("%s: %s", "-type", "unknown type");
  1040.     }
  1041.     
  1042.     new = palloc(N_TYPE, f_type);
  1043.     new->m_data = mask;
  1044.     return(new);
  1045. }
  1046.  
  1047. /*
  1048.  * -user uname functions --
  1049.  *
  1050.  *    True if the file belongs to the user uname.  If uname is numeric and
  1051.  *    an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
  1052.  *    return a valid user name, uname is taken as a user ID.
  1053.  */
  1054. int
  1055. #if __STDC__
  1056. f_user (PLAN *plan, FTSENT *entry)
  1057. #else
  1058. f_user(plan, entry)
  1059.     PLAN *plan;
  1060.     FTSENT *entry;
  1061. #endif
  1062. {
  1063. #if 0
  1064.     printf("%d : %d\n",(int)entry->fts_statb.st_uid , (int)plan->u_data);
  1065. #endif
  1066.     return(entry->fts_statb.st_uid == plan->u_data);
  1067. }
  1068.  
  1069. PLAN *
  1070. #if __STDC__
  1071. c_user (char *username)
  1072. #else
  1073. c_user(username)
  1074.     char *username;
  1075. #endif
  1076. {
  1077.     PLAN *new;
  1078.     struct passwd *p;
  1079.     uid_t uid;
  1080.     
  1081.     ftsoptions &= ~FTS_NOSTAT;
  1082.  
  1083.     p = getpwnam(username);
  1084.     if (p == NULL) {
  1085.         uid = atoi(username);
  1086.         if (uid == 0 && username[0] != '0')
  1087.             err("%s: %s", "-user", "no such user");
  1088.     } else
  1089.         uid = p->pw_uid;
  1090.  
  1091.     new = palloc(N_USER, f_user);
  1092.     new->u_data = uid;
  1093.     return(new);
  1094. }
  1095.  
  1096. /*
  1097.  * -xdev functions --
  1098.  *
  1099.  *    Always true, causes find not to decend past directories that have a
  1100.  *    different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
  1101.  */
  1102. PLAN *
  1103. #if __STDC__
  1104. c_xdev (void)
  1105. #else
  1106. c_xdev()
  1107. #endif
  1108. {
  1109.     ftsoptions |= FTS_XDEV;
  1110.  
  1111.     return(palloc(N_XDEV, f_always_true));
  1112. }
  1113.  
  1114. /*
  1115.  * ( expression ) functions --
  1116.  *
  1117.  *    True if expression is true.
  1118.  */
  1119. int
  1120. #if __STDC__
  1121. f_expr (PLAN *plan, FTSENT *entry)
  1122. #else
  1123. f_expr(plan, entry)
  1124.     PLAN *plan;
  1125.     FTSENT *entry;
  1126. #endif
  1127. {
  1128.     register PLAN *p;
  1129.     register int state;
  1130.  
  1131.     for (p = plan->p_data[0];
  1132.         p && (state = (p->eval)(p, entry)) != 0; p = p->next);
  1133.     return(state);
  1134. }
  1135.  
  1136. /*
  1137.  * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers.  They are
  1138.  * eliminated during phase 2 of find_formplan() --- the '(' node is converted
  1139.  * to a N_EXPR node containing the expression and the ')' node is discarded.
  1140.  */
  1141. PLAN *
  1142. #if __STDC__
  1143. c_openparen (void)
  1144. #else
  1145. c_openparen()
  1146. #endif
  1147. {
  1148.     return(palloc(N_OPENPAREN, (int (*)__P((PLAN *, FTSENT *)))-1));
  1149. }
  1150.  
  1151. PLAN *
  1152. #if __STDC__
  1153. c_closeparen (void)
  1154. #else
  1155. c_closeparen()
  1156. #endif
  1157. {
  1158.     return(palloc(N_CLOSEPAREN, (int (*) __P((PLAN *, FTSENT *)))-1));
  1159. }
  1160.  
  1161. /*
  1162.  * -mtime n functions --
  1163.  *
  1164.  *    True if the difference between the file modification time and the
  1165.  *    current time is n 24 hour periods.
  1166.  */
  1167. int
  1168. #if __STDC__
  1169. f_mtime (PLAN *plan, FTSENT *entry)
  1170. #else
  1171. f_mtime(plan, entry)
  1172.     PLAN *plan;
  1173.     FTSENT *entry;
  1174. #endif
  1175. {
  1176.     extern time_t now;
  1177.  
  1178.     COMPARE((now - entry->fts_statb.st_mtime + SECSPERDAY - 1) /
  1179.         SECSPERDAY, plan->t_data);
  1180. }
  1181.  
  1182. PLAN *
  1183. #if __STDC__
  1184. c_mtime (char *arg)
  1185. #else
  1186. c_mtime(arg)
  1187.     char *arg;
  1188. #endif
  1189. {
  1190.     PLAN *new;
  1191.  
  1192.     ftsoptions &= ~FTS_NOSTAT;
  1193.  
  1194.     new = palloc(N_MTIME, f_mtime);
  1195.     new->t_data = find_parsenum(new, "-mtime", arg, (char *)NULL);
  1196.     return(new);
  1197. }
  1198.  
  1199. /*
  1200.  * ! expression functions --
  1201.  *
  1202.  *    Negation of a primary; the unary NOT operator.
  1203.  */
  1204. int
  1205. #if __STDC__
  1206. f_not (PLAN *plan, FTSENT *entry)
  1207. #else
  1208. f_not(plan, entry)
  1209.     PLAN *plan;
  1210.     FTSENT *entry;
  1211. #endif
  1212. {
  1213.     register PLAN *p;
  1214.     register int state;
  1215.  
  1216.     for (p = plan->p_data[0];
  1217.         p && (state = (p->eval)(p, entry)) != 0; p = p->next);
  1218.     return(!state);
  1219. }
  1220.  
  1221. PLAN *
  1222. #if __STDC__
  1223. c_not (void)
  1224. #else
  1225. c_not()
  1226. #endif
  1227. {
  1228.     return(palloc(N_NOT, f_not));
  1229. }
  1230.  
  1231. /*
  1232.  * expression -o expression functions --
  1233.  *
  1234.  *    Alternation of primaries; the OR operator.  The second expression is
  1235.  * not evaluated if the first expression is true.
  1236.  */
  1237. int
  1238. #if __STDC__
  1239. f_or (PLAN *plan, FTSENT *entry)
  1240. #else
  1241. f_or(plan, entry)
  1242.     PLAN *plan;
  1243.     FTSENT *entry;
  1244. #endif
  1245. {
  1246.     register PLAN *p;
  1247.     register int state;
  1248.  
  1249.     for (p = plan->p_data[0];
  1250.         p && (state = (p->eval)(p, entry)) != 0; p = p->next);
  1251.  
  1252.     if (state)
  1253.         return(1);
  1254.  
  1255.     for (p = plan->p_data[1];
  1256.         p && (state = (p->eval)(p, entry)) != 0; p = p->next);
  1257.     return(state);
  1258. }
  1259.  
  1260. PLAN *
  1261. #if __STDC__
  1262. c_or (void)
  1263. #else
  1264. c_or()
  1265. #endif
  1266. {
  1267.     return(palloc(N_OR, f_or));
  1268. }
  1269.  
  1270. static PLAN *
  1271. #if __STDC__
  1272. palloc (enum ntype t, int (*f)(PLAN *, FTSENT *))
  1273. #else
  1274. palloc(t, f)
  1275.     enum ntype t;
  1276.     int (*f)();
  1277. #endif
  1278. {
  1279.     PLAN *new;
  1280.  
  1281.     if ((new = malloc(sizeof(PLAN))) != NULL) {
  1282.         new->type = t;
  1283.         new->eval = f;
  1284.         new->flags = 0;
  1285.         new->next = NULL;
  1286.         return(new);
  1287.     }
  1288.     err("%s", strerror(errno));
  1289.     /* NOTREACHED */
  1290. }
  1291.